www.gusucode.com > VC++ SMS 串口的阻塞模式短信彩信的收发-源码程序 > VC++ SMS 串口的阻塞模式短信彩信的收发-源码程序/code/SMS/myxmodem.cpp

    //Download by http://www.NewXing.com
// myxmodem.cpp: implementation of the myxmodem class.
//
//////////////////////////////////////////////////////////////////////

#include "myxmodem.h"
#include "Comm.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

#define SOH       0x01
#define EOT       0x04
#define ACK       0x06
#define NAK       0x15
#define CAN       0x18
#define CTRL_Z    0x1a
#define SPACE     0x20
#define ASCII_C   0x43
#define PACKET_DATA_BUFFER_LENGTH 128
#define MAX_TX_TRY 20


#define PRINT_BUFFER_LENGTH     80
#define COUNT_STEP               1
#define MAX_COUNT              100

#define MAX_MESSAGE_LEN   132

//xmodem support 1k define
#define CTRLZ 0x1A
#define STX  0x02
#define DLY_1S 1000
#define MAXRETRANS 25

//

struct  Message
{ 
    BYTE  Data_Len;                        /* 消息内容长度,即Message中的内容字节数 */ 
    BYTE message[PACKET_DATA_BUFFER_LENGTH];  /* 消息内容, 由发送进程填写 */ 
    void *User_Data;
}; 

static const unsigned short crc16tab[256]= {
	0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
	0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
	0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
	0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
	0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
	0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
	0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
	0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
	0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
	0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
	0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
	0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
	0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
	0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
	0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
	0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
	0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
	0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
	0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
	0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
	0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
	0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
	0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
	0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
	0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
	0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
	0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
	0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
	0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
	0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
	0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
	0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};

void myxmodem::send_a_byte(char c)
{
	unsigned char t[1];
	unsigned long wCount;
	t[0]=c;
	//WriteFile(hcom,t,1, &wCount, NULL);
	wCount = WriteComm(t, 1);
}

int myxmodem::get_a_byte(void) // msec timeout
{
    unsigned char t[1] = {0};
	unsigned long wCount;
	//ReadFile(hcom,t,1,&wCount,NULL);
	wCount = ReadComm(t, 1);
    return t[0];
}

BYTE myxmodem::tx_EOT(void)
{
    BYTE attempt;

    for(attempt = 1; attempt <= MAX_TX_TRY; attempt++)
    {
        send_a_byte(EOT);                                       // send file end
        if(get_a_byte() == ACK)  return 1;                     // file end acknowledged
    } 
    return 0;                                                          // file tx failed
}

UINT myxmodem::update_CRC(BYTE inData, UINT checksum)
{
	register unsigned short crc = checksum;
    return  (crc << 8) ^ crc16tab[ (crc >> 8) ^ inData ];
}  

BYTE myxmodem::tx_packet(BYTE packet_number,BYTE * packet_data_buffer, BYTE temp_char )
{
    BYTE attempt;
	unsigned long ncount;

    for(attempt = 1; attempt <= MAX_TX_TRY; attempt++)
    {    
        BYTE buffer_index;
        unsigned int checksum= 0;
		ncount=0;
        send_a_byte(SOH);                     // send start of packet
        send_a_byte(packet_number);            
        send_a_byte(255 - packet_number);

        for(buffer_index = 0; buffer_index < PACKET_DATA_BUFFER_LENGTH; buffer_index++)
        {
           // send_a_byte(packet_data_buffer[buffer_index]);
            if (temp_char == NAK) 
				checksum += packet_data_buffer[buffer_index];
            else
                checksum = update_CRC(packet_data_buffer[buffer_index], checksum);
        }

		while(ncount<PACKET_DATA_BUFFER_LENGTH)
		{
			//WriteFile(hcom,packet_data_buffer,PACKET_DATA_BUFFER_LENGTH,&ncount,NULL);
			ncount = WriteComm(packet_data_buffer, PACKET_DATA_BUFFER_LENGTH);
		}

        if (temp_char == ASCII_C)
            send_a_byte((char)((checksum>>8) & 0x00ff));
        send_a_byte((char)(checksum & 0x00ff));   // send end of packet CRC                                           
        temp_char = get_a_byte();            // get receiver response
        if (temp_char == CAN)  
			return 0;                     // reception cancelled
        if (temp_char == ACK)
            return 1;                     // packet received okay
    }

    return 0;                             // attempts exhausted
}

/*
function: 以XMODEM 发送数据
in:  user_data  是数据指针
out: 1    sucess
       o    faile
使用全局变量? 无       

*/
 
int myxmodem::send_packet_data(BYTE *User_Data , UINT LEN)
{
    struct  Message  Xmodem_Pack22;
	struct  Message  *xModem;
    BYTE i;
    unsigned char packet_number = 1;
    unsigned char no_more = 0;
    unsigned char temp_char = 0;
    xModem=&Xmodem_Pack22;
	xModem->User_Data=User_Data;

    while((temp_char != ASCII_C) && (temp_char != NAK))    
	{
		temp_char = get_a_byte();// wait till receiver ready
		if(temp_char == CAN) 
			return 0;
	}

	if (LEN < PACKET_DATA_BUFFER_LENGTH)
	{ 
		for(i=0;i<LEN;i++)	    
			xModem->message[i]=(*User_Data++); 
		for(i=LEN;i<128;i++)
			xModem->message[i]=CTRL_Z;    
        if(tx_packet(packet_number, xModem->message, temp_char)==0)
			return 0;    
	}
    else
	{
        do
		{
			for(i=0;i<128;i++)
				xModem->message[i]=(*User_Data++); 
			if(tx_packet(packet_number, xModem->message, temp_char)==0)
				return 0;
			packet_number++;
			LEN=LEN-128;
		}while(LEN>=128);
		if (LEN)
		{
			for(i=0;i<LEN;i++)
				xModem->message[i]=(*User_Data++);
			for(i=LEN;i<128;i++)
				xModem->message[i]=CTRL_Z;
			if( tx_packet(packet_number, xModem->message, temp_char)==0)
				return 0;    
		}
	}
	if (!tx_EOT())
        return 0;                      // end tx data failed

    return 1;
}


//xmodem 1k support begin
unsigned short myxmodem::crc16_ccitt(unsigned char *buf, int len)
{
	register int counter;
	register unsigned short crc = 0;
	for( counter = 0; counter < len; counter++)
		crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *(char *)buf++)&0x00FF];
	return crc;
}


void myxmodem::_outbyte(int c)
{
	unsigned char t[1];
	unsigned long wCount;
	t[0]=c;
	//WriteFile(hcom,t,1, &wCount, NULL);
	wCount = WriteComm(t, 1);
}

int myxmodem::_inbyte(unsigned short timeout) // msec timeout
{
    unsigned char t[1];
	unsigned long wCount;
	//ReadFile(hcom,t,1,&wCount,NULL);
	wCount = ReadComm(t, 1);
    return t[0];
}


int myxmodem::check(int crc, unsigned char *buf, int sz)
{
	if (crc) {
		unsigned short crc = crc16_ccitt(buf, sz);
		unsigned short tcrc = (buf[sz]<<8)+buf[sz+1];
		if (crc == tcrc)
			return 1;
	}
	else {
		int i;
		unsigned char cks = 0;
		for (i = 0; i < sz; ++i) {
			cks += buf[i];
		}
		if (cks == buf[sz])
		return 1;
	}

	return 0;
}

void myxmodem::flushinput(void)
{
	while (_inbyte(((DLY_1S)*3)>>1) >= 0)
		;
}
//********************************************
int myxmodem::recv_packet_data(unsigned char *dest, unsigned long destsz)
{
	unsigned char xbuff[MAX_MESSAGE_LEN+1]; // SOH | 信息包序号| 信息包序号的补码 | 数据区段(128)| 算术校验和
	unsigned char *p;
	int bufsz, crc = 0;
	unsigned char trychar = 'C';
	unsigned char packetno = 1;
	int i, c, len = 0;
	int retry, retrans = MAXRETRANS;

	for(;;) {
		for( retry = 0; retry < 16; ++retry) {
			if (trychar) send_a_byte(trychar);
			if ((c = get_a_byte()) >= 0) {
				switch (c) {
				case SOH:
					bufsz = 128;
					goto start_recv;
				case EOT:
					//flushinput();
					send_a_byte(ACK);
					return len; // normal end 
				case CAN:
					if ((c = get_a_byte()) == CAN) {
						flushinput();
						send_a_byte(ACK);
						return -1; // canceled by remote 
					}
					break;
				default:
					break;
				}
			}
		}
		if (trychar == 'C') { trychar = NAK; continue; }
		flushinput();
		send_a_byte(CAN);
		send_a_byte(CAN);
		send_a_byte(CAN);
		return -2; // sync error 

	start_recv:
		if (trychar == 'C') crc = 1;
		trychar = 0;
		p = xbuff;
		*p++ = c;
		
		for (i = 0;  i < (bufsz+(crc?1:0)+3); ++i) 
		{
			if ((c = get_a_byte())<0) goto reject;
			*p++ = c;
		}
		if (xbuff[1] == (unsigned char)(~xbuff[2]) && (xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&check(crc, &xbuff[3], bufsz)) 
		{
			if (xbuff[1] == packetno)	
			{
				int count = destsz - len;
				if (count > bufsz) count = bufsz;
				if (count > 0) 
				{
					memcpy (&dest[len], &xbuff[3], count);
					len += count;
				}
				++packetno;
				retrans = MAXRETRANS+1;
			}
			if (--retrans <= 0) 
			{
				flushinput();
				send_a_byte(CAN);
				send_a_byte(CAN);
				send_a_byte(CAN);
				return -3; // too many retry error 
			}
			send_a_byte(ACK);
			continue;
		}
	reject:
		//flushinput();
		send_a_byte(NAK);
	}
}
//************************************



/*
int myxmodem::xmodemReceive(unsigned char *dest, unsigned long destsz)
{
	unsigned char xbuff[1030]; // 1024 for XModem 1k + 3 head chars + 2 crc + nul 
	unsigned char *p;
	int bufsz, crc = 0;
	unsigned char trychar = 'C';
	unsigned char packetno = 1;
	int i, c, len = 0;
	int retry, retrans = MAXRETRANS;

	for(;;) {
		for( retry = 0; retry < 16; ++retry) {
			if (trychar) _outbyte(trychar);
			if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
				switch (c) {
				case SOH:
					bufsz = 128;
					goto start_recv;
				case STX:
					bufsz = 1024;
					goto start_recv;
				case EOT:
					flushinput();
					_outbyte(ACK);
					return len; // normal end 
				case CAN:
					if ((c = _inbyte(DLY_1S)) == CAN) {
						flushinput();
						_outbyte(ACK);
						return -1; // canceled by remote 
					}
					break;
				default:
					break;
				}
			}
		}
		if (trychar == 'C') { trychar = NAK; continue; }
		flushinput();
		_outbyte(CAN);
		_outbyte(CAN);
		_outbyte(CAN);
		return -2; // sync error 

	start_recv:
		if (trychar == 'C') crc = 1;
		trychar = 0;
		p = xbuff;
		*p++ = c;
		for (i = 0;  i < (bufsz+(crc?1:0)+3); ++i) {
			if ((c = _inbyte(DLY_1S)) < 0) goto reject;
			*p++ = c;
		}

		if (xbuff[1] == (unsigned char)(~xbuff[2]) && 
			(xbuff[1] == packetno || xbuff[1] == (unsigned char)packetno-1) &&
			check(crc, &xbuff[3], bufsz)) {
			if (xbuff[1] == packetno)	{
				register int count = destsz - len;
				if (count > bufsz) count = bufsz;
				if (count > 0) {
					memcpy (&dest[len], &xbuff[3], count);
					len += count;
				}
				++packetno;
				retrans = MAXRETRANS+1;
			}
			if (--retrans <= 0) {
				flushinput();
				_outbyte(CAN);
				_outbyte(CAN);
				_outbyte(CAN);
				return -3; // too many retry error 
			}
			_outbyte(ACK);
			continue;
		}
	reject:
		flushinput();
		_outbyte(NAK);
	}
}
*/
int myxmodem::xmodemTransmit(unsigned char *src, unsigned long srcsz)
{
	unsigned char xbuff[1030]; // 1024 for XModem 1k + 3 head chars + 2 crc + nul 
	int bufsz, crc = -1;
	unsigned char packetno = 1;
	int i, c, len = 0;
	int retry;

	for(;;) {
		for( retry = 0; retry < 16; ++retry) {
			if ((c = _inbyte((DLY_1S)<<1)) >= 0) {
				switch (c) {
				case 'C':
					crc = 1;
					goto start_trans;
				case NAK:
					crc = 0;
					goto start_trans;
				case CAN:
					if ((c = _inbyte(DLY_1S)) == CAN) {
						_outbyte(ACK);
						flushinput();
						return -1; // canceled by remote 
					}
					break;
				default:
					break;
				}
			}
		}
		_outbyte(CAN);
		_outbyte(CAN);
		_outbyte(CAN);
		flushinput();
		return -2; // no sync

		for(;;) {
		start_trans:
			xbuff[0] = SOH; bufsz = 128;
			xbuff[1] = packetno;
			xbuff[2] = ~packetno;
			c = srcsz - len;
			if (c > bufsz) c = bufsz;
			if (c >= 0) {
				memset (&xbuff[3], 0, bufsz);
				if (c == 0) {
					xbuff[3] = CTRLZ;
				}
				else {
					memcpy (&xbuff[3], &src[len], c);
					if (c < bufsz) xbuff[3+c] = CTRLZ;
				}
				if (crc) {
					unsigned short ccrc = crc16_ccitt(&xbuff[3], bufsz);
					xbuff[bufsz+3] = (ccrc>>8) & 0xFF;
					xbuff[bufsz+4] = ccrc & 0xFF;
				}
				else {
					unsigned char ccks = 0;
					for (i = 3; i < bufsz+3; ++i) {
						ccks += xbuff[i];
					}
					xbuff[bufsz+3] = ccks;
				}
				for (retry = 0; retry < MAXRETRANS; ++retry) {
					for (i = 0; i < bufsz+4+(crc?1:0); ++i) {
						_outbyte(xbuff[i]);
					}
					if ((c = _inbyte(DLY_1S)) >= 0 ) {
						switch (c) {
						case ACK:
							++packetno;
							len += bufsz;
							goto start_trans;
						case CAN:
							if ((c = _inbyte(DLY_1S)) == CAN) {
								_outbyte(ACK);
								flushinput();
								return -1; //canceled by remote 
							}
							break;
						case NAK:
						default:
							break;
						}
					}
				}
				_outbyte(CAN);
				_outbyte(CAN);
				_outbyte(CAN);
				flushinput();
				return -4; // xmit error 
			}
			else {
				for (retry = 0; retry < 10; ++retry) {
					_outbyte(EOT);
					if ((c = _inbyte((DLY_1S)<<1)) == ACK) break;
				}
				flushinput();
				return (c == ACK)?len:-5;
			}
		}
	}
}

myxmodem::myxmodem(HANDLE h)
{
	hcom=h;
}

myxmodem::~myxmodem()
{

}